APP Maze3D, &03baff1e
  CAPTION "Maze3D", 1
  ICON "Maze3D.mbm"
ENDA

DECLARE EXTERNAL

INCLUDE "SYSTEM.OXH"

REM
REM                                       Maze3D
REM
REM                               Version 5.1 (10/21/98)
REM
REM
REM      Generate and solve mazes on your Psion Series 5.
REM
REM      The mazes are displayed in three dimensions.
REM
REM      You will be prompted for a random number seed, the number of columns,
REM  the tilt, and the number of mazes to be tried before one is selected for
REM  display.
REM
REM      While the maze is being generated, a spinning cursor is displayed.
REM
REM      After the maze is displayed, you may use the arrow keys to solve it.
REM Press "Q" to quit or press "S" to have the computer solve the maze.
REM
REM      After the maze is solved, you must press some key to continue.
REM
REM      Each maze has exactly one solution that does not involve backtracking
REM (passing through a doorway more than once).
REM
REM      This program was written by James L. Dean.
REM
REM

EXTERNAL ConditionallyIncrementAdjacency:
EXTERNAL DisplayQuadrilateral:(XMax,XOffset,YMax,X0,Y0,Z0,X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,Shade%)
EXTERNAL DisplaySolution:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
EXTERNAL DrawLine:(X1,Y1,X2,Y2,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
EXTERNAL DrawQuadrilateral:(ColorNum%)
EXTERNAL GenerateMaze:(MaxX%,MaxY%,NumColumns%,NumRows%)
EXTERNAL GetCorner:(X,Y,Z,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
EXTERNAL Hash:
EXTERNAL Increment:
EXTERNAL LetUserTryToSolve:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
EXTERNAL Maze3D:
EXTERNAL NoPassageIfWall:(X%,Y%,MaxX%)
EXTERNAL OutputFrontTop:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
EXTERNAL OutputLeftRight:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
EXTERNAL OutputMaze:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
EXTERNAL SelectMaze:(Seed&,MaxX%,MaxY%,NumRoomsInMaze%,NumColumns%,NumRows%,NumTrials%)
EXTERNAL SolveMaze:(MaxX%,MaxY%)
EXTERNAL Titillate:

CONST True%=-1
CONST False%=0

CONST NumColors%=16
CONST TopColor%=226
CONST FrontWallShade%=113
CONST FloorShade%=178
CONST RightWallShade%=81
CONST LeftWallShade%=81
CONST BackoutShade%=146
CONST AdvanceShade%=0
CONST SolutionShade%=255
CONST WidthOfGraphicsInInches=5.6
CONST NumXPixels%=640
CONST WidthOfGraphicsInPixels%=640
CONST HeightOfGraphicsInInches=2.0
CONST NumYPixels%=240
CONST HeightOfGraphicsInPixels%=220
CONST RelativeWidthOfWall=0.2:REM relative to side of square
CONST RelativeHeightOfWall=1.0:REM relative to side of square
CONST MinWallLengthInPixels%=24
CONST MinNumColumns%=2
CONST MaxNumColumns%=26:REM INT(FLT(WidthOfGraphicsInPixels%)/FLT(MinWallLengthInPixels%)-FLT(RelativeWidthOfWall))
CONST MaxNumRows%=9:REM INT(HeightOfGraphicsInInches*FLT(NumColumns%)/WidthOfGraphicsInInches)
CONST MaxNumRooms%=234:REM MaxNumRows%*MaxNumColumns%
CONST MaxMaxX%=52:REM 2*MaxNumColumns%
CONST MaxMaxXPlus1%=53:REM MaxMaxX%+1
CONST MaxMaxY%=18:REM 2*MaxNumRows%
CONST MaxMaxYPlus1%=19:REM MaxMaxY%+1
CONST MaxPageSize%=1007:REM MaxMaxXPlus1%*MaxMaxYPlus1%

PROC Maze3D:
  GLOBAL ComputerPage%(MaxPageSize%)
  GLOBAL DeltaX%(96)
  GLOBAL DeltaY%(96)
  GLOBAL StackIndex1%(MaxNumRooms%)
  GLOBAL StackIndex2%(MaxNumRooms%)
  GLOBAL SubstitutionHigh%(100)
  GLOBAL SubstitutionLow%(100)
  GLOBAL Titillator$(4,1)
  GLOBAL TitillatorIndex%
  GLOBAL UserInput$(1)
  GLOBAL UserPage%(MaxPageSize%)
  LOCAL ColorNum%
  LOCAL ColumnCount&
  LOCAL CosTilt
  LOCAL DefaultNumColumns%
  LOCAL DefaultNumTrials%
  LOCAL DefaultSeed&
  LOCAL DefaultTilt
  LOCAL DeltaIndex1a%
  LOCAL DeltaIndex1b%
  LOCAL DeltaIndex1c%
  LOCAL DeltaIndex1d%
  LOCAL DeltaIndex2%
  LOCAL IniFile$(255)
  LOCAL MaxX%
  LOCAL MaxY%
  LOCAL NumColumns%
  LOCAL NumRoomsInMaze%
  LOCAL NumRows%
  LOCAL NumTrials%
  LOCAL PixelsPerX
  LOCAL PixelsPerZ
  LOCAL Plot%
  LOCAL Radians
  LOCAL RadiansPerDegree
  LOCAL RelDistOfUserFromScreen
  LOCAL Response%
  LOCAL Seed&
  LOCAL SinTilt
  LOCAL Tem
  LOCAL Tilt
  LOCAL TrialCount&
  LOCAL XMax
  LOCAL XOffset
  LOCAL YMax

  Titillator$(1)="|"
  Titillator$(2)="/"
  Titillator$(3)="-"
  Titillator$(4)="\"
  SubstitutionHigh%(1)=4
  SubstitutionHigh%(2)=1
  SubstitutionHigh%(3)=2
  SubstitutionHigh%(4)=8
  SubstitutionHigh%(5)=8
  SubstitutionHigh%(6)=9
  SubstitutionHigh%(7)=9
  SubstitutionHigh%(8)=6
  SubstitutionHigh%(9)=5
  SubstitutionHigh%(10)=7
  SubstitutionHigh%(11)=2
  SubstitutionHigh%(12)=1
  SubstitutionHigh%(13)=2
  SubstitutionHigh%(14)=9
  SubstitutionHigh%(15)=8
  SubstitutionHigh%(16)=8
  SubstitutionHigh%(17)=6
  SubstitutionHigh%(18)=3
  SubstitutionHigh%(19)=5
  SubstitutionHigh%(20)=1
  SubstitutionHigh%(21)=9
  SubstitutionHigh%(22)=5
  SubstitutionHigh%(23)=4
  SubstitutionHigh%(24)=4
  SubstitutionHigh%(25)=9
  SubstitutionHigh%(26)=8
  SubstitutionHigh%(27)=6
  SubstitutionHigh%(28)=0
  SubstitutionHigh%(29)=8
  SubstitutionHigh%(30)=0
  SubstitutionHigh%(31)=6
  SubstitutionHigh%(32)=0
  SubstitutionHigh%(33)=2
  SubstitutionHigh%(34)=4
  SubstitutionHigh%(35)=1
  SubstitutionHigh%(36)=9
  SubstitutionHigh%(37)=2
  SubstitutionHigh%(38)=0
  SubstitutionHigh%(39)=7
  SubstitutionHigh%(40)=4
  SubstitutionHigh%(41)=7
  SubstitutionHigh%(42)=3
  SubstitutionHigh%(43)=0
  SubstitutionHigh%(44)=0
  SubstitutionHigh%(45)=2
  SubstitutionHigh%(46)=6
  SubstitutionHigh%(47)=8
  SubstitutionHigh%(48)=9
  SubstitutionHigh%(49)=4
  SubstitutionHigh%(50)=0
  SubstitutionHigh%(51)=8
  SubstitutionHigh%(52)=3
  SubstitutionHigh%(53)=2
  SubstitutionHigh%(54)=3
  SubstitutionHigh%(55)=2
  SubstitutionHigh%(56)=5
  SubstitutionHigh%(57)=2
  SubstitutionHigh%(58)=4
  SubstitutionHigh%(59)=6
  SubstitutionHigh%(60)=9
  SubstitutionHigh%(61)=7
  SubstitutionHigh%(62)=9
  SubstitutionHigh%(63)=1
  SubstitutionHigh%(64)=3
  SubstitutionHigh%(65)=5
  SubstitutionHigh%(66)=7
  SubstitutionHigh%(67)=1
  SubstitutionHigh%(68)=1
  SubstitutionHigh%(69)=4
  SubstitutionHigh%(70)=5
  SubstitutionHigh%(71)=8
  SubstitutionHigh%(72)=1
  SubstitutionHigh%(73)=6
  SubstitutionHigh%(74)=0
  SubstitutionHigh%(75)=5
  SubstitutionHigh%(76)=7
  SubstitutionHigh%(77)=8
  SubstitutionHigh%(78)=2
  SubstitutionHigh%(79)=3
  SubstitutionHigh%(80)=3
  SubstitutionHigh%(81)=7
  SubstitutionHigh%(82)=3
  SubstitutionHigh%(83)=5
  SubstitutionHigh%(84)=1
  SubstitutionHigh%(85)=7
  SubstitutionHigh%(86)=5
  SubstitutionHigh%(87)=4
  SubstitutionHigh%(88)=0
  SubstitutionHigh%(89)=3
  SubstitutionHigh%(90)=6
  SubstitutionHigh%(91)=3
  SubstitutionHigh%(92)=7
  SubstitutionHigh%(93)=7
  SubstitutionHigh%(94)=1
  SubstitutionHigh%(95)=9
  SubstitutionHigh%(96)=4
  SubstitutionHigh%(97)=0
  SubstitutionHigh%(98)=5
  SubstitutionHigh%(99)=6
  SubstitutionHigh%(100)=6
  SubstitutionLow%(1)=1
  SubstitutionLow%(2)=2
  SubstitutionLow%(3)=2
  SubstitutionLow%(4)=1
  SubstitutionLow%(5)=5
  SubstitutionLow%(6)=5
  SubstitutionLow%(7)=4
  SubstitutionLow%(8)=6
  SubstitutionLow%(9)=4
  SubstitutionLow%(10)=6
  SubstitutionLow%(11)=4
  SubstitutionLow%(12)=4
  SubstitutionLow%(13)=5
  SubstitutionLow%(14)=6
  SubstitutionLow%(15)=6
  SubstitutionLow%(16)=3
  SubstitutionLow%(17)=0
  SubstitutionLow%(18)=9
  SubstitutionLow%(19)=6
  SubstitutionLow%(20)=5
  SubstitutionLow%(21)=7
  SubstitutionLow%(22)=2
  SubstitutionLow%(23)=0
  SubstitutionLow%(24)=9
  SubstitutionLow%(25)=3
  SubstitutionLow%(26)=4
  SubstitutionLow%(27)=2
  SubstitutionLow%(28)=3
  SubstitutionLow%(29)=9
  SubstitutionLow%(30)=1
  SubstitutionLow%(31)=9
  SubstitutionLow%(32)=9
  SubstitutionLow%(33)=9
  SubstitutionLow%(34)=3
  SubstitutionLow%(35)=8
  SubstitutionLow%(36)=9
  SubstitutionLow%(37)=3
  SubstitutionLow%(38)=4
  SubstitutionLow%(39)=1
  SubstitutionLow%(40)=5
  SubstitutionLow%(41)=0
  SubstitutionLow%(42)=5
  SubstitutionLow%(43)=2
  SubstitutionLow%(44)=7
  SubstitutionLow%(45)=0
  SubstitutionLow%(46)=8
  SubstitutionLow%(47)=8
  SubstitutionLow%(48)=0
  SubstitutionLow%(49)=4
  SubstitutionLow%(50)=5
  SubstitutionLow%(51)=0
  SubstitutionLow%(52)=3
  SubstitutionLow%(53)=6
  SubstitutionLow%(54)=8
  SubstitutionLow%(55)=1
  SubstitutionLow%(56)=7
  SubstitutionLow%(57)=8
  SubstitutionLow%(58)=8
  SubstitutionLow%(59)=7
  SubstitutionLow%(60)=1
  SubstitutionLow%(61)=3
  SubstitutionLow%(62)=2
  SubstitutionLow%(63)=7
  SubstitutionLow%(64)=7
  SubstitutionLow%(65)=1
  SubstitutionLow%(66)=8
  SubstitutionLow%(67)=0
  SubstitutionLow%(68)=3
  SubstitutionLow%(69)=7
  SubstitutionLow%(70)=5
  SubstitutionLow%(71)=2
  SubstitutionLow%(72)=6
  SubstitutionLow%(73)=4
  SubstitutionLow%(74)=0
  SubstitutionLow%(75)=9
  SubstitutionLow%(76)=9
  SubstitutionLow%(77)=7
  SubstitutionLow%(78)=7
  SubstitutionLow%(79)=4
  SubstitutionLow%(80)=6
  SubstitutionLow%(81)=2
  SubstitutionLow%(82)=0
  SubstitutionLow%(83)=0
  SubstitutionLow%(84)=1
  SubstitutionLow%(85)=7
  SubstitutionLow%(86)=3
  SubstitutionLow%(87)=6
  SubstitutionLow%(88)=6
  SubstitutionLow%(89)=1
  SubstitutionLow%(90)=1
  SubstitutionLow%(91)=2
  SubstitutionLow%(92)=4
  SubstitutionLow%(93)=5
  SubstitutionLow%(94)=9
  SubstitutionLow%(95)=8
  SubstitutionLow%(96)=2
  SubstitutionLow%(97)=8
  SubstitutionLow%(98)=8
  SubstitutionLow%(99)=3
  SubstitutionLow%(100)=5
  DeltaX%(1)=-1
  DeltaY%(1)=0
  DeltaX%(25)=0
  DeltaY%(25)=1
  DeltaX%(49)=1
  DeltaY%(49)=0
  DeltaX%(73)=0
  DeltaY%(73)=-1
  DeltaIndex2%=0
  DeltaIndex1a%=0
  WHILE DeltaIndex1a% <= 3
    DeltaIndex1b%=0
    WHILE DeltaIndex1b% <= 3
      IF DeltaIndex1a% <> DeltaIndex1b%
        DeltaIndex1c%=0
        WHILE DeltaIndex1c% <= 3
          IF (DeltaIndex1a% <> DeltaIndex1c%) AND (DeltaIndex1b% <> DeltaIndex1c%)
            DeltaIndex1d%=0
            WHILE DeltaIndex1d% <= 3
              IF (DeltaIndex1a% <> DeltaIndex1d%) AND (DeltaIndex1b% <> DeltaIndex1d%) AND (DeltaIndex1c% <> DeltaIndex1d%)
                DeltaIndex2%=DeltaIndex2%+1
                DeltaX%(24*DeltaIndex1a%+DeltaIndex2%)=DeltaX%(1)
                DeltaY%(24*DeltaIndex1a%+DeltaIndex2%)=DeltaY%(1)
                DeltaX%(24*DeltaIndex1b%+DeltaIndex2%)=DeltaX%(25)
                DeltaY%(24*DeltaIndex1b%+DeltaIndex2%)=DeltaY%(25)
                DeltaX%(24*DeltaIndex1c%+DeltaIndex2%)=DeltaX%(49)
                DeltaY%(24*DeltaIndex1c%+DeltaIndex2%)=DeltaY%(49)
                DeltaX%(24*DeltaIndex1d%+DeltaIndex2%)=DeltaX%(73)
                DeltaY%(24*DeltaIndex1d%+DeltaIndex2%)=DeltaY%(73)
              ENDIF
              DeltaIndex1d%=DeltaIndex1d%+1
            ENDWH
          ENDIF
          DeltaIndex1c%=DeltaIndex1c%+1
        ENDWH
      ENDIF
      DeltaIndex1b%=DeltaIndex1b%+1
    ENDWH
    DeltaIndex1a%=DeltaIndex1a%+1
  ENDWH
  IniFile$=CMD$(1)
  IniFile$=LEFT$(IniFile$,LEN(IniFile$)-3)+"ini"
  IF EXIST(IniFile$)
    OPEN IniFile$,A,DefaultNumColumns%,DefaultTilt,DefaultSeed&,DefaultNumTrials%
    DefaultNumColumns%=A.DefaultNumColumns%
    DefaultTilt=A.DefaultTilt
    DefaultSeed&=A.DefaultSeed&
    DefaultNumTrials%=A.DefaultNumTrials%
    CLOSE
  ELSE
    DefaultNumColumns%=26
    DefaultTilt=60.0
    DefaultSeed&=1
    DefaultNumTrials%=5
  ENDIF
  DO
    ColumnCount&=DefaultNumColumns%
    Tilt=DefaultTilt
    TrialCount&=DefaultNumTrials%
    Seed&=DefaultSeed&
	  DINIT "3D Mazes", 16
    DLONG Seed&, "Random number seed:", 1, 99999999
	  DLONG ColumnCount&, "Number of columns:", MinNumColumns%, MaxNumColumns%
	  DFLOAT Tilt, "Tilt (degrees):", 30.0, 60.0
    DLONG TrialCount&, "Display most difficult maze of:", 1, 50
	  DBUTTONS "Okay", %o, "Quit", %q
  	Response%=DIALOG
    IF Response% = %o
      NumColumns%=ColumnCount&
      NumTrials%=TrialCount&
      Tem=NumColumns%
      NumRows%=INT(HeightOfGraphicsInInches*Tem/WidthOfGraphicsInInches)
      IF NumRows% < 2
        NumRows%=2
      ENDIF
      DefaultSeed&=Seed&
      DefaultNumColumns%=NumColumns%
      DefaultNumTrials%=NumTrials%
      DefaultTilt=Tilt
      MaxX%=2*NumColumns%
      MaxY%=2*NumRows%
      NumRoomsInMaze%=NumRows%*NumColumns%
      Plot%=GCREATE(0,0,640,240,1,2)
      GSETPENWIDTH 1
      TitillatorIndex%=1
      SelectMaze:(Seed&,MaxX%,MaxY%,NumRoomsInMaze%,NumColumns%,NumRows%,NumTrials%)
      GCOLOR 255,255,255
      GAT 320,120
      GPRINT Titillator$(TitillatorIndex%)
      RadiansPerDegree=ATAN(1.0)/45.0
      Radians=Tilt*RadiansPerDegree
      SinTilt=SIN(Radians)
      CosTilt=COS(Radians)
      Tem=NumColumns%
      XMax=Tem+RelativeWidthOfWall
      Tem=WidthOfGraphicsInPixels%
      PixelsPerX=(Tem-1.0)/(XMax*(XMax/(XMax-RelativeHeightOfWall)))
      XOffset=(XMax/2.0)*(RelativeHeightOfWall/(XMax-RelativeHeightOfWall))
      Tem=NumRows%
      YMax=Tem+RelativeWidthOfWall
      Tem=HeightOfGraphicsInPixels%
      PixelsPerZ=(Tem-1.0)/SQR(YMax*YMax+RelativeHeightOfWall*RelativeHeightOfWall)
      IF YMax > XMax
        RelDistOfUserFromScreen=YMax
      ELSE
        RelDistOfUserFromScreen=XMax
      ENDIF
      OutputMaze:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
      GCOLOR 0,0,0
      GAT 320-GTWIDTH("Arrows - Move    S - Solve    D - Dialog")/2,234
      GPRINT "Arrows - Move    S - Solve    D - Dialog"
      ComputerPage%((MaxX%+1)*MaxY%+MaxX%)=1
      LetUserTryToSolve:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
      IF (UserInput$ = "s") OR (UserInput$ = "S")
        DisplaySolution:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
        GCOLOR 0,0,0
        GAT 320-GTWIDTH("Press a key to continue.")/2,234
        GPRINT "Press a key to continue."
        GET$
      ENDIF
      GCLOSE Plot%
    ENDIF
  UNTIL Response% <> %o
  IF EXIST(IniFile$)
    DELETE IniFile$
  ENDIF
  CREATE IniFile$,A,DefaultNumColumns%,DefaultTilt,DefaultSeed&,DefaultNumTrials%
  A.DefaultNumColumns%=DefaultNumColumns%
  A.DefaultTilt=DefaultTilt
  A.DefaultSeed&=DefaultSeed&
  A.DefaultNumTrials%=DefaultNumTrials%
  APPEND
  CLOSE
ENDP

PROC DrawQuadrilateral:(ColorNum%)
  EXTERNAL BoxX%()
  EXTERNAL BoxY%()
  GLOBAL BoxX1%
  GLOBAL BoxX2%
  GLOBAL BoxY1%
  LOCAL BoxDeltaX
  LOCAL BoxDeltaY
  LOCAL BoxNum1%
  LOCAL BoxNum2%
  LOCAL BoxXIntercept
  LOCAL BoxYMax%
  LOCAL BoxYMin%
  LOCAL BoxYOffset
  LOCAL InterceptCountMod2%

  BoxYMin%=BoxY%(1)
  BoxYMax%=BoxYMin%
  BoxNum1%=2
  WHILE BoxNum1% <= 4
    IF BoxY%(BoxNum1%) < BoxYMin%
      BoxYMin%=BoxY%(BoxNum1%)
    ENDIF
    IF BoxY%(BoxNum1%) > BoxYMax%
      BoxYMax%=BoxY%(BoxNum1%)
    ENDIF
    BoxNum1%=BoxNum1%+1
  ENDWH
  GCOLOR ColorNum%,ColorNum%,ColorNum%
  BoxY1%=BoxYMin%
  WHILE BoxY1% <= BoxYMax%
    InterceptCountMod2%=0
    BoxNum2%=2
    BoxNum1%=1
    WHILE BoxNum1% <= 4
      IF BoxY%(BoxNum1%) >= BoxY1%
        IF BoxY1% > BoxY%(BoxNum2%)
          BoxDeltaY=BoxY%(BoxNum2%)-BoxY%(BoxNum1%)
          BoxDeltaX=BoxX%(BoxNum2%)-BoxX%(BoxNum1%)
          BoxYOffset=BoxY1%-BoxY%(BoxNum1%)
          BoxXIntercept=BoxX%(BoxNum1%)
          BoxX1%=INT((BoxDeltaX*BoxYOffset)/BoxDeltaY+BoxXIntercept)
          IF InterceptCountMod2% = 0
            BoxX2%=BoxX1%
          ELSE
            GAT BoxX1%,BoxY1%
            GLINETO BoxX2%,BoxY1%
            GLINEBY 0,0
          ENDIF
          InterceptCountMod2%=1-InterceptCountMod2%
        ENDIF
      ELSE
        IF BoxY1% <= BoxY%(BoxNum2%)
          BoxDeltaY=BoxY%(BoxNum2%)-BoxY%(BoxNum1%)
          BoxDeltaX=BoxX%(BoxNum2%)-BoxX%(BoxNum1%)
          BoxYOffset=BoxY1%-BoxY%(BoxNum1%)
          BoxXIntercept=BoxX%(BoxNum1%)
          BoxX1%=INT((BoxDeltaX*BoxYOffset)/BoxDeltaY+BoxXIntercept)
          IF InterceptCountMod2% = 0
            BoxX2%=BoxX1%
          ELSE
            GAT BoxX1%,BoxY1%
            GLINETO BoxX2%,BoxY1%
            GLINEBY 0,0
          ENDIF
          InterceptCountMod2%=1-InterceptCountMod2%
        ENDIF
      ENDIF
      BoxNum2%=BoxNum2%+1
      IF BoxNum2% > 4
        BoxNum2%=1
      ENDIF
      BoxNum1%=BoxNum1%+1
    ENDWH
    BoxY1%=BoxY1%+1
  ENDWH
ENDP

PROC GetCorner:(X,Y,Z,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
  EXTERNAL CornerX%
  EXTERNAL CornerY%
  LOCAL XAdjusted
  LOCAL YPrime
  LOCAL ZAdjusted
  LOCAL ZPrime

  YPrime=(YMax-Y)*CosTilt-Z*SinTilt
  ZPrime=(YMax-Y)*SinTilt+Z*CosTilt
  ZAdjusted=(YMax/2.0)+RelDistOfUserFromScreen*(ZPrime-(YMax/2.0))/(YPrime+RelDistOfUserFromScreen)
  XAdjusted=(XMax/2.0)+RelDistOfUserFromScreen*(X-(XMax/2.0))/(YPrime+RelDistOfUserFromScreen)
  XAdjusted=XAdjusted+XOffset
  CornerX%=INT(PixelsPerX*XAdjusted)
  CornerY%=(HeightOfGraphicsInPixels%-1)-INT(PixelsPerZ*ZAdjusted)
ENDP

PROC DisplayQuadrilateral:(XMax,XOffset,YMax,X0,Y0,Z0,X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,Shade%)
  GLOBAL BoxX%(4)
  GLOBAL BoxY%(4)
  GLOBAL CornerX%
  GLOBAL CornerY%
  GetCorner:(X0,Y0,Z0,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
  BoxX%(1)=CornerX%
  BoxY%(1)=CornerY%
  GetCorner:(X1,Y1,Z1,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
  BoxX%(2)=CornerX%
  BoxY%(2)=CornerY%
  GetCorner:(X2,Y2,Z2,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
  BoxX%(3)=CornerX%
  BoxY%(3)=CornerY%
  GetCorner:(X3,Y3,Z3,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
  BoxX%(4)=CornerX%
  BoxY%(4)=CornerY%
  DrawQuadrilateral:(Shade%)
ENDP

PROC OutputFrontTop:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
  EXTERNAL SingleRectangleX()
  EXTERNAL SingleRectangleY()
  LOCAL X0
  LOCAL X1
  LOCAL X2
  LOCAL X3
  LOCAL Y0
  LOCAL Y1
  LOCAL Y2
  LOCAL Y3
  X0=SingleRectangleX(4)
  Y0=SingleRectangleY(4)
  X1=SingleRectangleX(3)
  Y1=SingleRectangleY(3)
  X2=SingleRectangleX(3)
  Y2=SingleRectangleY(3)
  X3=SingleRectangleX(4)
  Y3=SingleRectangleY(4)
  DisplayQuadrilateral:(XMax,XOffset,YMax,X0,Y0,RelativeHeightOfWall,X1,Y1,RelativeHeightOfWall,X2,Y2,0.0,X3,Y3,0.0,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,FrontWallShade%)
  X0=SingleRectangleX(1)
  Y0=SingleRectangleY(1)
  X1=SingleRectangleX(2)
  Y1=SingleRectangleY(2)
  X2=SingleRectangleX(3)
  Y2=SingleRectangleY(3)
  X3=SingleRectangleX(4)
  Y3=SingleRectangleY(4)
  DisplayQuadrilateral:(XMax,XOffset,YMax,X0,Y0,RelativeHeightOfWall,X1,Y1,RelativeHeightOfWall,X2,Y2,RelativeHeightOfWall,X3,Y3,RelativeHeightOfWall,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,TopColor%)
ENDP

PROC OutputLeftRight:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
  EXTERNAL SingleRectangleX()
  EXTERNAL SingleRectangleY()
  LOCAL X0
  LOCAL X1
  LOCAL X2
  LOCAL X3
  LOCAL Y0
  LOCAL Y1
  LOCAL Y2
  LOCAL Y3
  IF 2.0*SingleRectangleX(1) > XMax
    X0=SingleRectangleX(1)
    Y0=SingleRectangleY(1)
    X1=SingleRectangleX(4)
    Y1=SingleRectangleY(4)
    X2=SingleRectangleX(4)
    Y2=SingleRectangleY(4)
    X3=SingleRectangleX(1)
    Y3=SingleRectangleY(1)
    DisplayQuadrilateral:(XMax,XOffset,YMax,X0,Y0,RelativeHeightOfWall,X1,Y1,RelativeHeightOfWall,X2,Y2,0.0,X3,Y3,0.0,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,RightWallShade%)
  ENDIF
  IF 2.0*SingleRectangleX(2) < XMax
    X0=SingleRectangleX(3)
    Y0=SingleRectangleY(3)
    X1=SingleRectangleX(2)
    Y1=SingleRectangleY(2)
    X2=SingleRectangleX(2)
    Y2=SingleRectangleY(2)
    X3=SingleRectangleX(3)
    Y3=SingleRectangleY(3)
    DisplayQuadrilateral:(XMax,XOffset,YMax,X0,Y0,RelativeHeightOfWall,X1,Y1,RelativeHeightOfWall,X2,Y2,0.0,X3,Y3,0.0,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,LeftWallShade%)
  ENDIF
ENDP

PROC OutputMaze:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
  EXTERNAL ComputerPage%()
  GLOBAL SingleRectangleX(4)
  GLOBAL SingleRectangleY(4)
  LOCAL BaseRectangleX(16)
  LOCAL BaseRectangleY(16)
  LOCAL RectangleX(16)
  LOCAL RectangleY(16)
  LOCAL VertexIndex%
  LOCAL VertexNum%
  LOCAL X%
  LOCAL X0
  LOCAL X1
  LOCAL X2
  LOCAL X3
  LOCAL Y%
  LOCAL Y0
  LOCAL Y1
  LOCAL Y2
  LOCAL Y3
  LOCAL YOffset
  BaseRectangleX(1)=0.0
  BaseRectangleY(1)=0.0
  BaseRectangleX(2)=RelativeWidthOfWall
  BaseRectangleY(2)=0.0
  BaseRectangleX(3)=RelativeWidthOfWall
  BaseRectangleY(3)=RelativeWidthOfWall
  BaseRectangleX(4)=0.0
  BaseRectangleY(4)=RelativeWidthOfWall
  BaseRectangleX(5)=RelativeWidthOfWall
  BaseRectangleY(5)=0.0
  BaseRectangleX(6)=1.0
  BaseRectangleY(6)=0.0
  BaseRectangleX(7)=1.0
  BaseRectangleY(7)=RelativeWidthOfWall
  BaseRectangleX(8)=RelativeWidthOfWall
  BaseRectangleY(8)=RelativeWidthOfWall
  BaseRectangleX(9)=RelativeWidthOfWall
  BaseRectangleY(9)=RelativeWidthOfWall
  BaseRectangleX(10)=1.0
  BaseRectangleY(10)=RelativeWidthOfWall
  BaseRectangleX(11)=1.0
  BaseRectangleY(11)=1.0
  BaseRectangleX(12)=RelativeWidthOfWall
  BaseRectangleY(12)=1.0
  BaseRectangleX(13)=0.0
  BaseRectangleY(13)=RelativeWidthOfWall
  BaseRectangleX(14)=RelativeWidthOfWall
  BaseRectangleY(14)=RelativeWidthOfWall
  BaseRectangleX(15)=RelativeWidthOfWall
  BaseRectangleY(15)=1.0
  BaseRectangleX(16)=0.0
  BaseRectangleY(16)=1.0
  RectangleX(1)=0.0
  RectangleY(1)=0.0
  RectangleX(2)=XMax
  RectangleY(2)=0.0
  RectangleX(3)=XMax
  RectangleY(3)=YMax
  RectangleX(4)=0.0
  RectangleY(4)=YMax
  X0=RectangleX(1)
  Y0=RectangleY(1)
  X1=RectangleX(2)
  Y1=RectangleY(2)
  X2=RectangleX(3)
  Y2=RectangleY(3)
  X3=RectangleX(4)
  Y3=RectangleY(4)
  DisplayQuadrilateral:(XMax,XOffset,YMax,X0,Y0,0.0,X1,Y1,0.0,X2,Y2,0.0,X3,Y3,0.0,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,FloorShade%)
  YOffset=0.0
  Y%=0
  WHILE Y% <= MaxY%
    VertexIndex%=1
    WHILE VertexIndex% <= 4
      RectangleX(VertexIndex%)=BaseRectangleX(VertexIndex%)
      RectangleY(VertexIndex%)=BaseRectangleY(VertexIndex%)+YOffset
      VertexIndex%=VertexIndex%+1
    ENDWH
    X%=0
    WHILE X% <= MaxX%
      IF ComputerPage%((MaxX%+1)*Y%+X%+1) = 0
        VertexIndex%=1
        WHILE VertexIndex% <= 4
          SingleRectangleX(VertexIndex%)=RectangleX(VertexIndex%)
          SingleRectangleY(VertexIndex%)=RectangleY(VertexIndex%)
          VertexIndex%=VertexIndex%+1
        ENDWH
        OutputLeftRight:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
      ENDIF
      VertexIndex%=1
      WHILE VertexIndex% <= 4
        RectangleX(VertexIndex%)=RectangleX(VertexIndex%)+1
        VertexIndex%=VertexIndex%+1
      ENDWH
      X%=X%+2
    ENDWH
    VertexIndex%=1
    WHILE VertexIndex% <= 4
      RectangleX(VertexIndex%)=BaseRectangleX(VertexIndex%)
      RectangleY(VertexIndex%)=BaseRectangleY(VertexIndex%)+YOffset
      VertexIndex%=VertexIndex%+1
    ENDWH
    VertexIndex%=5
    WHILE VertexIndex% <= 9
      RectangleX(VertexIndex%)=BaseRectangleX(VertexIndex%)
      RectangleY(VertexIndex%)=BaseRectangleY(VertexIndex%)+YOffset
      VertexIndex%=VertexIndex%+1
    ENDWH
    X%=0
    WHILE X% <= MaxX%
      IF ComputerPage%((MaxX%+1)*Y%+X%+1) = 0
        VertexIndex%=1
        WHILE VertexIndex% <= 4
          SingleRectangleX(VertexIndex%)=RectangleX(VertexIndex%)
          SingleRectangleY(VertexIndex%)=RectangleY(VertexIndex%)
          VertexIndex%=VertexIndex%+1
        ENDWH
        OutputFrontTop:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
      ENDIF
      VertexIndex%=1
      WHILE VertexIndex% <= 4
        RectangleX(VertexIndex%)=RectangleX(VertexIndex%)+1
        VertexIndex%=VertexIndex%+1
      ENDWH
      X%=X%+1
      IF X% <= MaxX%
        IF ComputerPage%((MaxX%+1)*Y%+X%+1) = 0
          VertexIndex%=4
          VertexNum%=1
          WHILE VertexNum% <= 4
            VertexIndex%=VertexIndex%+1
            SingleRectangleX(VertexNum%)=RectangleX(VertexIndex%)
            SingleRectangleY(VertexNum%)=RectangleY(VertexIndex%)
            VertexNum%=VertexNum%+1
          ENDWH
          OutputFrontTop:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
        ENDIF
        VertexIndex%=5
        WHILE VertexIndex% <= 9
          RectangleX(VertexIndex%)=RectangleX(VertexIndex%)+1
          VertexIndex%=VertexIndex%+1
        ENDWH
        X%=X%+1
      ENDIF
    ENDWH
    Y%=Y%+1
    IF Y% <= MaxY%
      VertexIndex%=13
      WHILE VertexIndex% <= 16
        RectangleX(VertexIndex%)=BaseRectangleX(VertexIndex%)
        RectangleY(VertexIndex%)=BaseRectangleY(VertexIndex%)+YOffset
        VertexIndex%=VertexIndex%+1
      ENDWH
      X%=0
      WHILE X% <= MaxX%
        IF ComputerPage%((MaxX%+1)*Y%+X%+1) = 0
          VertexIndex%=12
          VertexNum%=1
          WHILE VertexNum% <= 4
            VertexIndex%=VertexIndex%+1
            SingleRectangleX(VertexNum%)=RectangleX(VertexIndex%)
            SingleRectangleY(VertexNum%)=RectangleY(VertexIndex%)
            VertexNum%=VertexNum%+1
          ENDWH
          OutputLeftRight:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
        ENDIF
        VertexIndex%=13
        WHILE VertexIndex% <= 16
          RectangleX(VertexIndex%)=RectangleX(VertexIndex%)+1
          VertexIndex%=VertexIndex%+1
        ENDWH
        X%=X%+2
      ENDWH
      VertexIndex%=13
      WHILE VertexIndex% <= 16
        RectangleX(VertexIndex%)=BaseRectangleX(VertexIndex%)
        RectangleY(VertexIndex%)=BaseRectangleY(VertexIndex%)+YOffset
        VertexIndex%=VertexIndex%+1
      ENDWH
      X%=0
      WHILE X% <= MaxX%
        IF ComputerPage%((MaxX%+1)*Y%+X%+1) = 0
          VertexIndex%=12
          VertexNum%=1
          WHILE VertexNum% <= 4
            VertexIndex%=VertexIndex%+1
            SingleRectangleX(VertexNum%)=RectangleX(VertexIndex%)
            SingleRectangleY(VertexNum%)=RectangleY(VertexIndex%)
            VertexNum%=VertexNum%+1
          ENDWH
          OutputFrontTop:(XMax,XOffset,YMax,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen)
        ENDIF
        VertexIndex%=13
        WHILE VertexIndex% <= 16
          RectangleX(VertexIndex%)=RectangleX(VertexIndex%)+1
          VertexIndex%=VertexIndex%+1
        ENDWH
        X%=X%+2
      ENDWH
      Y%=Y%+1
    ENDIF
    YOffset=YOffset+1
  ENDWH
ENDP

PROC Titillate:
  EXTERNAL Titillator$()
  EXTERNAL TitillatorIndex%
  GCOLOR 255,255,255
  GAT 320,120
  GPRINT Titillator$(TitillatorIndex%)
  TitillatorIndex%=TitillatorIndex%+1
  IF TitillatorIndex% > 4
    TitillatorIndex%=1
  ENDIF
  GCOLOR 0,0,0
  GAT 320,120
  GPRINT Titillator$(TitillatorIndex%)
ENDP

PROC ConditionallyIncrementAdjacency:
  EXTERNAL Adjacency%
  EXTERNAL ComputerPage%()
  EXTERNAL PageOffset%
  IF ComputerPage%(PageOffset%) = 1
    Adjacency%=Adjacency%+1
  ENDIF
ENDP

PROC SolveMaze:(MaxX%,MaxY%)
  EXTERNAL Adjacency%
  EXTERNAL ComputerPage%()
  EXTERNAL DeltaX%()
  EXTERNAL DeltaY%()
  EXTERNAL NumRoomsInSolution%
  EXTERNAL StackIndex1%()
  GLOBAL PageOffset%
  LOCAL DeltaIndex%
  LOCAL DeltaOffset%
  LOCAL PassageFound%
  LOCAL StackHead%
  LOCAL X%
  LOCAL XNext%
  LOCAL Y%
  LOCAL YNext%

  NumRoomsInSolution%=1
  Adjacency%=0
  X%=1
  Y%=1
  StackHead%=0
  ComputerPage%(MaxX%+3)=1
  DO
    DeltaIndex%=0
    PassageFound%=False%
    DO
      WHILE (DeltaIndex% < 4) AND (NOT PassageFound%)
        DeltaOffset%=24*DeltaIndex%+1
        XNext%=X%+DeltaX%(DeltaOffset%)
        YNext%=Y%+DeltaY%(DeltaOffset%)
        IF ComputerPage%((MaxX%+1)*YNext%+XNext%+1) = 2
          PassageFound%=True%
        ELSE
          DeltaIndex%=DeltaIndex%+1
        ENDIF
      ENDWH
      IF NOT PassageFound%
        DeltaIndex%=StackIndex1%(StackHead%)
        ComputerPage%((MaxX%+1)*Y%+X%+1)=2
        DeltaOffset%=24*DeltaIndex%+1
        X%=X%-DeltaX%(DeltaOffset%)
        Y%=Y%-DeltaY%(DeltaOffset%)
        ComputerPage%((MaxX%+1)*Y%+X%+1)=2
        X%=X%-DeltaX%(DeltaOffset%)
        Y%=Y%-DeltaY%(DeltaOffset%)
        StackHead%=StackHead%-1
        DeltaIndex%=DeltaIndex%+1
      ENDIF
    UNTIL PassageFound%
    ComputerPage%((MaxX%+1)*YNext%+XNext%+1)=1
    DeltaOffset%=24*DeltaIndex%+1
    XNext%=XNext%+DeltaX%(DeltaOffset%)
    YNext%=YNext%+DeltaY%(DeltaOffset%)
    IF YNext% <= MaxY%
      StackHead%=StackHead%+1
      StackIndex1%(StackHead%)=DeltaIndex%
      ComputerPage%((MaxX%+1)*YNext%+XNext%+1)=1
      X%=XNext%
      Y%=YNext%
    ENDIF
  UNTIL YNext% >= MaxY%
  X%=MaxX%-1
  Y%=MaxY%-1
  Adjacency%=0
  WHILE (StackHead% > 0)
    DeltaOffset%=1
    DeltaIndex%=0
    WHILE DeltaIndex% <= 3
      XNext%=X%+DeltaX%(DeltaOffset%)
      YNext%=Y%+DeltaY%(DeltaOffset%)
      PageOffset%=(MaxX%+1)*YNext%+XNext%+1
      IF ComputerPage%(PageOffset%) <> 1
        IF ComputerPage%(PageOffset%) = 0
          XNext%=XNext%+DeltaX%(DeltaOffset%)
          YNext%=YNext%+DeltaY%(DeltaOffset%)
          IF XNext% < 0
            Adjacency%=Adjacency%+1
          ELSE
            IF XNext% > MaxX%
              Adjacency%=Adjacency%+1
            ELSE
              IF YNext% < 0
                Adjacency%=Adjacency%+1
              ELSE
                IF YNext% > MaxY%
                  Adjacency%=Adjacency%+1
                ELSE
                  PageOffset%=(MaxX%+1)*YNext%+XNext%+1
                  ConditionallyIncrementAdjacency:
                ENDIF
              ENDIF
            ENDIF
          ENDIF
        ENDIF
      ENDIF
      DeltaOffset%=DeltaOffset%+24
      DeltaIndex%=DeltaIndex%+1
    ENDWH
    DeltaOffset%=24*StackIndex1%(StackHead%)+1
    X%=X%-2*DeltaX%(DeltaOffset%)
    Y%=Y%-2*DeltaY%(DeltaOffset%)
    StackHead%=StackHead%-1
    NumRoomsInSolution%=NumRoomsInSolution%+1
  ENDWH
  DeltaOffset%=1
  DeltaIndex%=0
  WHILE DeltaIndex% <= 3
    XNext%=X%+DeltaX%(DeltaOffset%)
    YNext%=X%+DeltaY%(DeltaOffset%)
    PageOffset%=(MaxX%+1)*YNext%+XNext%+1
    IF ComputerPage%(PageOffset%) <> 2
      IF ComputerPage%(PageOffset%) = 0
        XNext%=XNext%+DeltaX%(DeltaOffset%)
        YNext%=YNext%+DeltaY%(DeltaOffset%)
        IF XNext% < 0
          Adjacency%=Adjacency%+1
        ELSE
          IF XNext% > MaxX%
            Adjacency%=Adjacency%+1
          ELSE
            IF YNext% < 0
              Adjacency%=Adjacency%+1
            ELSE
              IF YNext% > MaxY%
                Adjacency%=Adjacency%+1
              ELSE
                PageOffset%=(MaxX%+1)*YNext%+XNext%+1
                ConditionallyIncrementAdjacency:
              ENDIF
            ENDIF
          ENDIF
        ENDIF
      ENDIF
    ENDIF
    DeltaOffset%=DeltaOffset%+24
    DeltaIndex%=DeltaIndex%+1
  ENDWH
ENDP

PROC GenerateMaze:(MaxX%,MaxY%,NumColumns%,NumRows%)
  EXTERNAL ComputerPage%()
  EXTERNAL DeltaX%()
  EXTERNAL DeltaY%()
  EXTERNAL SeedByte%()
  EXTERNAL StackIndex1%()
  EXTERNAL StackIndex2%()
  EXTERNAL Titillator$()
  EXTERNAL TitillatorIndex%
  LOCAL DeltaIndex1%
  LOCAL DeltaIndex2%
  LOCAL DeltaOffset%
  LOCAL Digit%
  LOCAL DigitNum%
  LOCAL PageOffset%
  LOCAL PassageFound%
  LOCAL RN%(8)
  LOCAL RNIndex1%
  LOCAL RNIndex2%
  LOCAL SearchComplete%
  LOCAL StackHead%
  LOCAL Sum%
  LOCAL TemInt%
  LOCAL X%
  LOCAL XNext%
  LOCAL Y%
  LOCAL YNext%

  Titillate:
  RN%(1)=SeedByte%(1)+1
  RN%(2)=SeedByte%(2)+1
  RN%(3)=SeedByte%(3)+1
  RN%(4)=SeedByte%(4)+1
  RN%(5)=SeedByte%(5)+1
  RN%(6)=SeedByte%(6)+1
  RN%(7)=SeedByte%(7)+1
  RN%(8)=SeedByte%(8)+1
  PageOffset%=0
  Y%=0
  WHILE Y% <= MaxY%
    X%=0
    WHILE X% <= MaxX%
      PageOffset%=PageOffset%+1
       ComputerPage%(PageOffset%)=0
      X%=X%+1
    ENDWH
    Y%=Y%+1
  ENDWH
  Sum%=0
  DigitNum%=1
  WHILE DigitNum% <= 3
    Digit%=RN%(1)
    RNIndex1%=1
    RNIndex2%=2
    WHILE (RNIndex2% <= 8)
      TemInt%=RN%(RNIndex2%)
      RN%(RNIndex1%)=TemInt%
      Digit%=Digit%+TemInt%
      IF Digit% >= 29
        Digit%=Digit%-29
      ENDIF
      RNIndex1%=RNIndex2%
      RNIndex2%=RNIndex2%+1
    ENDWH
    RN%(8)=Digit%
    Sum%=29*Sum%+Digit%
    DigitNum%=DigitNum%+1
  ENDWH
  X%=2*MOD&:(Sum%,NumColumns%)+1
  Sum%=0
  DigitNum%=1
  WHILE DigitNum% <= 3
    Digit%=RN%(1)
    RNIndex1%=1
    RNIndex2%=2
    WHILE (RNIndex2% <= 8)
      TemInt%=RN%(RNIndex2%)
      RN%(RNIndex1%)=TemInt%
      Digit%=Digit%+TemInt%
      IF Digit% >= 29
        Digit%=Digit%-29
      ENDIF
      RNIndex1%=RNIndex2%
      RNIndex2%=RNIndex2%+1
    ENDWH
    RN%(8)=Digit%
    Sum%=29*Sum%+Digit%
    DigitNum%=DigitNum%+1
  ENDWH
  Y%=2*MOD&:(Sum%,NumRows%)+1
  ComputerPage%((MaxX%+1)*Y%+X%+1)=2
  StackHead%=0
  DO
    DeltaIndex1%=0
    DO
      DeltaIndex2%=RN%(1)
      RNIndex1%=1
      RNIndex2%=2
      WHILE (RNIndex2% <= 8)
        TemInt%=RN%(RNIndex2%)
        RN%(RNIndex1%)=TemInt%
        DeltaIndex2%=DeltaIndex2%+TemInt%
        IF DeltaIndex2% >= 29
          DeltaIndex2%=DeltaIndex2%-29
        ENDIF
        RNIndex1%=RNIndex2%
        RNIndex2%=RNIndex2%+1
      ENDWH
      RN%(8)=DeltaIndex2%
    UNTIL DeltaIndex2% < 24
    PassageFound%=False%
    SearchComplete%=False%
    WHILE (NOT SearchComplete%)
      WHILE ((DeltaIndex1% < 4) AND (NOT PassageFound%))
        DeltaOffset%=24*DeltaIndex1%+DeltaIndex2%+1
        XNext%=X%+2*DeltaX%(DeltaOffset%)
        IF XNext% <= 0
          DeltaIndex1%=DeltaIndex1%+1
        ELSE
          IF XNext% > MaxX%
            DeltaIndex1%=DeltaIndex1%+1
          ELSE
            YNext%=Y%+2*DeltaY%(DeltaOffset%)
            IF YNext% <= 0
              DeltaIndex1%=DeltaIndex1%+1
            ELSE
              IF YNext% > MaxY%
                DeltaIndex1%=DeltaIndex1%+1
              ELSE
                IF ComputerPage%((MaxX%+1)*YNext%+XNext%+1) = 0
                  PassageFound%=True%
                ELSE
                  DeltaIndex1%=DeltaIndex1%+1
                ENDIF
              ENDIF
            ENDIF
          ENDIF
        ENDIF
      ENDWH
      IF NOT PassageFound%
        IF StackHead% > 0
          DeltaIndex1%=StackIndex1%(StackHead%)
          DeltaIndex2%=StackIndex2%(StackHead%)
          DeltaOffset%=24*DeltaIndex1%+DeltaIndex2%+1
          X%=X%-2*DeltaX%(DeltaOffset%)
          Y%=Y%-2*DeltaY%(DeltaOffset%)
          StackHead%=StackHead%-1
          DeltaIndex1%=DeltaIndex1%+1
        ENDIF
      ENDIF
      IF ((PassageFound%) OR ((StackHead% = 0) AND (DeltaIndex1% >= 4)))
        SearchComplete%=True%
      ELSE
        SearchComplete%=False%
      ENDIF
    ENDWH
    IF PassageFound%
      StackHead%=StackHead%+1
      StackIndex1%(StackHead%)=DeltaIndex1%
      StackIndex2%(StackHead%)=DeltaIndex2%
      ComputerPage%((MaxX%+1)*YNext%+XNext%+1)=2
      ComputerPage%((MaxX%+1)*((Y%+YNext%)/2)+(X%+XNext%)/2+1)=2
      X%=XNext%
      Y%=YNext%
    ENDIF
  UNTIL StackHead% = 0
  ComputerPage%(2)=1
  ComputerPage%((MaxX%+1)*MaxY%+MaxX%)=2
ENDP

PROC SelectMaze:(Seed&,MaxX%,MaxY%,NumRoomsInMaze%,NumColumns%,NumRows%,NumTrials%)
  EXTERNAL ComputerPage%()
  EXTERNAL StackIndex1%()
  EXTERNAL StackIndex2%()
  EXTERNAL Titillator$()
  EXTERNAL TitillatorIndex%
  GLOBAL Adjacency%
  GLOBAL NumRoomsInSolution%
  GLOBAL SeedByte%(8)
  GLOBAL Counter0%
  GLOBAL Counter1%
  GLOBAL Counter2%
  GLOBAL Counter3%
  GLOBAL Counter4%
  GLOBAL Counter5%
  GLOBAL Counter6%
  GLOBAL Counter7%
  LOCAL DigitNum%
  LOCAL Dividend&
  LOCAL MinAdjacency%
  LOCAL NumRoomsInSolutionAtMin%
  LOCAL Quotient&
  LOCAL RN%(8)
  LOCAL SeedByteAtMin%(8)
  LOCAL TrialNum%

  Dividend&=Seed&
  DigitNum%=1
  WHILE DigitNum% <= 8
    Quotient&=Dividend&/10
    RN%(DigitNum%)=Dividend&-10*Quotient&
    Dividend&=Quotient&
    DigitNum%=DigitNum%+1
  ENDWH
  Counter0%=RN%(1)
  Counter1%=RN%(2)
  Counter2%=RN%(3)
  Counter3%=RN%(4)
  Counter4%=RN%(5)
  Counter5%=RN%(6)
  Counter6%=RN%(7)
  Counter7%=RN%(8)
  Hash:
  MinAdjacency%=2*NumRoomsInMaze%+1
  NumRoomsInSolutionAtMin%=0
  SeedByteAtMin%(1)=Counter0%
  SeedByteAtMin%(2)=Counter1%
  SeedByteAtMin%(3)=Counter2%
  SeedByteAtMin%(4)=Counter3%
  SeedByteAtMin%(5)=Counter4%
  SeedByteAtMin%(6)=Counter5%
  SeedByteAtMin%(7)=Counter6%
  SeedByteAtMin%(8)=Counter7%
  TrialNum%=NumTrials%
  WHILE TrialNum% >= 1
    Titillate:
    SeedByte%(1)=Counter0%
    SeedByte%(2)=Counter1%
    SeedByte%(3)=Counter2%
    SeedByte%(4)=Counter3%
    SeedByte%(5)=Counter4%
    SeedByte%(6)=Counter5%
    SeedByte%(7)=Counter6%
    SeedByte%(8)=Counter7%
    GenerateMaze:(MaxX%,MaxY%,NumColumns%,NumRows%)
    SolveMaze:(MaxX%,MaxY%)
    IF 3*NumRoomsInSolution% >= NumRoomsInMaze%
      IF Adjacency% < MinAdjacency%
        MinAdjacency%=Adjacency%
        NumRoomsInSolutionAtMin%=NumRoomsInSolution%
        SeedByteAtMin%(1)=SeedByte%(1)
        SeedByteAtMin%(2)=SeedByte%(2)
        SeedByteAtMin%(3)=SeedByte%(3)
        SeedByteAtMin%(4)=SeedByte%(4)
        SeedByteAtMin%(5)=SeedByte%(5)
        SeedByteAtMin%(6)=SeedByte%(6)
        SeedByteAtMin%(7)=SeedByte%(7)
        SeedByteAtMin%(8)=SeedByte%(8)
      ELSE
        IF Adjacency% = MinAdjacency%
          IF NumRoomsInSolution% > NumRoomsInSolutionAtMin%
            NumRoomsInSolutionAtMin%=NumRoomsInSolution%
            SeedByteAtMin%(1)=SeedByte%(1)
            SeedByteAtMin%(2)=SeedByte%(2)
            SeedByteAtMin%(3)=SeedByte%(3)
            SeedByteAtMin%(4)=SeedByte%(4)
            SeedByteAtMin%(5)=SeedByte%(5)
            SeedByteAtMin%(6)=SeedByte%(6)
            SeedByteAtMin%(7)=SeedByte%(7)
            SeedByteAtMin%(8)=SeedByte%(8)
          ENDIF
        ENDIF
      ENDIF
    ENDIF
    Increment:
    TrialNum%=TrialNum%-1
  ENDWH
  SeedByte%(1)=SeedByteAtMin%(1)
  SeedByte%(2)=SeedByteAtMin%(2)
  SeedByte%(3)=SeedByteAtMin%(3)
  SeedByte%(4)=SeedByteAtMin%(4)
  SeedByte%(5)=SeedByteAtMin%(5)
  SeedByte%(6)=SeedByteAtMin%(6)
  SeedByte%(7)=SeedByteAtMin%(7)
  SeedByte%(8)=SeedByteAtMin%(8)
  GenerateMaze:(MaxX%,MaxY%,NumColumns%,NumRows%)
  SolveMaze:(MaxX%,MaxY%)
ENDP

PROC Hash:
  EXTERNAL Counter0%
  EXTERNAL Counter1%
  EXTERNAL Counter2%
  EXTERNAL Counter3%
  EXTERNAL Counter4%
  EXTERNAL Counter5%
  EXTERNAL Counter6%
  EXTERNAL Counter7%
  EXTERNAL SubstitutionHigh%()
  EXTERNAL SubstitutionLow%()
  LOCAL Iteration%
  LOCAL Seed0%
  LOCAL Seed1%
  LOCAL Seed2%
  LOCAL Seed3%
  LOCAL Seed4%
  LOCAL Seed5%
  LOCAL Seed6%
  LOCAL Seed7%
  LOCAL SubstitutionIndex%
  LOCAL Tem0%
  LOCAL Tem1%
  LOCAL Tem2%
  Seed0%=Counter0%
  Seed1%=Counter1%
  Seed2%=Counter2%
  Seed3%=Counter3%
  Seed4%=Counter4%
  Seed5%=Counter5%
  Seed6%=Counter6%
  Seed7%=Counter7%
  Iteration%=1
  WHILE Iteration% <= 8
    SubstitutionIndex%=10*Seed1%+Seed0%+1
    Tem0%=SubstitutionLow%(SubstitutionIndex%)
    Tem1%=SubstitutionHigh%(SubstitutionIndex%)
    SubstitutionIndex%=10*Seed3%+Seed2%+1
    Seed0%=SubstitutionLow%(SubstitutionIndex%)
    Tem2%=SubstitutionHigh%(SubstitutionIndex%)
    SubstitutionIndex%=10*Seed5%+Seed4%+1
    Seed2%=SubstitutionLow%(SubstitutionIndex%)
    Seed1%=SubstitutionHigh%(SubstitutionIndex%)
    SubstitutionIndex%=10*Seed7%+Seed6%+1
    Seed5%=SubstitutionLow%(SubstitutionIndex%)
    Seed7%=SubstitutionHigh%(SubstitutionIndex%)
    Seed3%=Tem0%
    Seed6%=Tem1%
    Seed4%=Tem2%
    Iteration%=Iteration%+1
  ENDWH
  Counter0%=Seed0%
  Counter1%=Seed1%
  Counter2%=Seed2%
  Counter3%=Seed3%
  Counter4%=Seed4%
  Counter5%=Seed5%
  Counter6%=Seed6%
  Counter7%=Seed7%
ENDP

PROC Increment:
  EXTERNAL Counter0%
  EXTERNAL Counter1%
  EXTERNAL Counter2%
  EXTERNAL Counter3%
  EXTERNAL Counter4%
  EXTERNAL Counter5%
  EXTERNAL Counter6%
  EXTERNAL Counter7%
  LOCAL Tem%
  Tem%=Counter0%+1
  IF Tem% <= 9
    Counter0%=Tem%
  ELSE
    Counter0%=0
    Tem%=Counter1%+1
    IF Tem% <= 9
      Counter1%=Tem%
    ELSE
      Counter1%=0
      Tem%=Counter2%+1
      IF Tem% <= 9
        Counter2%=Tem%
      ELSE
        Counter2%=0
        Tem%=Counter3%+1
        IF Tem% <= 9
          Counter3%=Tem%
        ELSE
          Counter3%=0
          Tem%=Counter4%+1
          IF Tem% <= 9
            Counter4%=Tem%
          ELSE
            Counter4%=0
            Tem%=Counter5%+1
            IF Tem% <= 9
              Counter5%=Tem%
            ELSE
              Counter5%=0
              Tem%=Counter6%+1
              IF Tem% <= 9
                Counter6%=Tem%
              ELSE
                Counter6%=0
                Tem%=Counter7%+1
                IF Tem% <= 9
                  Counter7%=Tem%
                ELSE
                  Counter7%=0
                ENDIF
              ENDIF
            ENDIF
          ENDIF
        ENDIF
      ENDIF
    ENDIF
  ENDIF
ENDP

PROC DrawLine:(X1,Y1,X2,Y2,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
  GLOBAL CornerX%
  GLOBAL CornerY%
  LOCAL LineX1%
  LOCAL LineX2%
  LOCAL LineY1%
  LOCAL LineY2%
  GetCorner:(X1,Y1,RelativeHeightOfWall,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
  LineX1%=CornerX%
  LineY1%=CornerY%
  GetCorner:(X2,Y2,RelativeHeightOfWall,PixelsPerX,PixelsPerZ,CosTilt,SinTilt,RelDistOfUserFromScreen,XMax,XOffset,YMax)
  LineX2%=CornerX%
  LineY2%=CornerY%
  GAT LineX1%,LineY1%
  GLINETO LineX2%,LineY2%
  GLINEBY 0,0
ENDP

PROC DisplaySolution:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
  EXTERNAL ComputerPage%()
  EXTERNAL DeltaX%()
  EXTERNAL DeltaY%()
  LOCAL DeltaIndex%
  LOCAL DeltaOffset%
  LOCAL PathFound%
  LOCAL Tem
  LOCAL X%
  LOCAL XNext%
  LOCAL XPrevious%
  LOCAL XRelative
  LOCAL XRelativeNext
  LOCAL Y%
  LOCAL YNext%
  LOCAL YPrevious%
  LOCAL YRelative
  LOCAL YRelativeNext
  GSETPENWIDTH 3
  XPrevious%=1
  YPrevious%=-1
  X%=1
  XRelative=(RelativeWidthOfWall+1.0)/2.0
  Y%=0
  YRelative=RelativeWidthOfWall/2.0
  DO
    PathFound%=False%
    DeltaIndex%=0
    WHILE NOT PathFound%
      DeltaOffset%=24*DeltaIndex%+1
      XNext%=X%+DeltaX%(DeltaOffset%)
      YNext%=Y%+DeltaY%(DeltaOffset%)
      IF (XNext% <> XPrevious%) OR (YNext% <> YPrevious%)
        IF ComputerPage%((MaxX%+1)*YNext%+XNext%+1) = 1
          PathFound%=True%
          Tem=DeltaX%(DeltaOffset%)
          XRelativeNext=XRelative+Tem/2.0
          Tem=DeltaY%(DeltaOffset%)
          YRelativeNext=YRelative+Tem/2.0
        ENDIF
      ENDIF
      DeltaIndex%=DeltaIndex%+1
    ENDWH
    DrawLine:(XRelative,YRelative,XRelativeNext,YRelativeNext,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ, RelDistOfUserFromScreen)
    XRelative=XRelativeNext
    YRelative=YRelativeNext
    XPrevious%=X%
    YPrevious%=Y%
    X%=XNext%
    Y%=YNext%
  UNTIL (X% = MaxX%-1) AND (Y% = MaxY%)
  GSETPENWIDTH 1
ENDP

PROC NoPassageIfWall:(X%,Y%,MaxX%)
  EXTERNAL PassageFound%
  EXTERNAL UserPage%()
  IF UserPage%((MaxX%+1)*Y%+X%+1) = 0
    PassageFound%=False%
  ENDIF
ENDP

PROC LetUserTryToSolve:(MaxX%,MaxY%,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
  EXTERNAL ComputerPage%()
  EXTERNAL DeltaX%()
  EXTERNAL DeltaY%()
  EXTERNAL UserInput$
  EXTERNAL UserPage%()
  GLOBAL PassageFound%
  LOCAL DeltaIndex1%
  LOCAL DeltaOffset%
  LOCAL PageOffset%
  LOCAL Pitch%
  LOCAL Response%
  LOCAL Tem
  LOCAL X%
  LOCAL XNext%
  LOCAL XRelative
  LOCAL XRelativeNext
  LOCAL Y%
  LOCAL YNext%
  LOCAL YRelative
  LOCAL YRelativeNext

  PageOffset%=0
  Y%=0
  WHILE Y% <= MaxY%
    X%=0
    WHILE X% <= MaxX%
      PageOffset%=PageOffset%+1
      IF ComputerPage%(PageOffset%) = 0
        UserPage%(PageOffset%)=0
      ELSE
        UserPage%(PageOffset%)=2
      ENDIF
      X%=X%+1
    ENDWH
    Y%=Y%+1
  ENDWH
  X%=1
  XRelative=(RelativeWidthOfWall+1.0)/2.0
  Y%=1
  YRelative=(RelativeWidthOfWall+1.0)/2.0
  UserPage%((MaxX%+1)*Y%+X%+1)=1
  GSETPENWIDTH 3
  GCOLOR AdvanceShade%,AdvanceShade%,AdvanceShade%
  DrawLine:(XRelative,RelativeWidthOfWall/2.0,XRelative,YRelative,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
  DO
    DO
      PassageFound%=True%
      UserInput$=GET$
      IF ((UserInput$ <> "D") AND (UserInput$ <> "d") AND (UserInput$ <> "S") AND (UserInput$ <> "s"))
        Response%=ASC(UserInput$)
        IF Response% = 8
          DeltaIndex1%=0
        ELSE
          IF Response% = 3
            DeltaIndex1%=0
          ELSE
            IF Response% = 0
              DeltaIndex1%=3
            ELSE
              IF Response% = 2
                DeltaIndex1%=2
              ELSE
                IF Response% = 1
                  DeltaIndex1%=1
                ELSE
                  PassageFound%=False%
                ENDIF
              ENDIF
            ENDIF
          ENDIF
        ENDIF
        UserInput$=" "
        IF PassageFound%
          DeltaOffset%=24*DeltaIndex1%+1
          XNext%=X%+DeltaX%(DeltaOffset%)
          IF XNext% <= 0
            PassageFound%=False%
          ELSE
            IF XNext% >= MaxX%
              PassageFound%=False%
            ELSE
              YNext%=Y%+DeltaY%(DeltaOffset%)
              IF YNext% <= 0
                PassageFound%=False%
              ELSE
                IF YNext% > MaxY%
                  PassageFound%=False%
                ELSE
                  NoPassageIfWall:(XNext%,YNext%,MaxX%)
                ENDIF
              ENDIF
            ENDIF
          ENDIF
        ENDIF
        IF NOT PassageFound%
          BEEP 4,300
        ENDIF
      ENDIF
    UNTIL (PassageFound%) OR (UserInput$ = "D") OR (UserInput$ = "d") OR (UserInput$ = "S") OR (UserInput$ = "s")
    IF ((UserInput$ <> "D") AND (UserInput$ <> "d") AND (UserInput$ <> "S") AND (UserInput$ <> "s"))
      DeltaOffset%=24*DeltaIndex1%+1
      XNext%=XNext%+DeltaX%(DeltaOffset%)
      YNext%=YNext%+DeltaY%(DeltaOffset%)
      IF YNext% < MaxY%
        IF UserPage%((MaxX%+1)*YNext%+XNext%+1) = 1
          GCOLOR BackoutShade%,BackoutShade%,BackoutShade%
          UserPage%((MaxX%+1)*Y%+X%+1)=2
        ELSE
          GCOLOR AdvanceShade%,AdvanceShade%,AdvanceShade%
          UserPage%((MaxX%+1)*YNext%+XNext%+1)=1
        ENDIF
        Tem=XNext%-X%
        XRelativeNext=XRelative+Tem/2.0
        Tem=YNext%-Y%
        YRelativeNext=YRelative+Tem/2.0
        DrawLine:(XRelative,YRelative,XRelativeNext,YRelativeNext,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
      ELSE
        GCOLOR AdvanceShade%,AdvanceShade%,AdvanceShade%
        DrawLine:(XRelative,YRelative,XRelative,YRelative+0.5,XMax,XOffset,YMax,CosTilt,SinTilt,PixelsPerX,PixelsPerZ,RelDistOfUserFromScreen)
      ENDIF
      X%=XNext%
      Y%=YNext%
      XRelative=XRelativeNext
      YRelative=YRelativeNext
    ENDIF
  UNTIL (YNext% >= MaxY%) OR (UserInput$ = "D") OR (UserInput$ = "d") OR (UserInput$ = "S") OR (UserInput$ = "s")
  GSETPENWIDTH 1
  GCOLOR 255,255,255
  GAT 320-GTWIDTH("Arrows - Move    S - Solve    D - Dialog")/2,234
  GPRINT "Arrows - Move    S - Solve    D - Dialog"
  IF ((UserInput$ <> "D") AND (UserInput$ <> "d") AND (UserInput$ <> "S") AND (UserInput$ <> "s"))
    GCOLOR 0,0,0
    GAT 320-GTWIDTH("Congratulations!")/2,234
    GPRINT "Congratulations!"
    Pitch%=1000
    WHILE Pitch% > 169
      BEEP 1,Pitch%
      Pitch%=Pitch%-33
    ENDWH
    GCOLOR 255,255,255
    GAT 320-GTWIDTH("Congratulations!")/2,234
    GPRINT "Congratulations!"
    GCOLOR 0,0,0
    GAT 320-GTWIDTH("S - Solve    Other - Dialog")/2,234
    GPRINT "S - Solve    Other - Dialog"
    UserInput$=GET$
    GCOLOR 255,255,255
    GAT 320-GTWIDTH("S - Solve    Other - Dialog")/2,234
    GPRINT "S - Solve    Other - Dialog"
  ENDIF
ENDP
